home *** CD-ROM | disk | FTP | other *** search
- // BEGIN FLOCK GPL
- //
- // Copyright Flock Inc. 2005-2007
- // http://flock.com
- //
- // This file may be used under the terms of of the
- // GNU General Public License Version 2 or later (the "GPL"),
- // http://www.gnu.org/licenses/gpl.html
- //
- // Software distributed under the License is distributed on an "AS IS" basis,
- // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- // for the specific language governing rights and limitations under the
- // License.
- //
- // END FLOCK GPL
-
- const MS_CONTRACTID = "@flock.com/metrics-service;1";
- const MS_CLASSID = Components.ID("{bc1358fa-6e36-4d0d-a401-b0b02111114c}");
- const MS_CLASSNAME = "Flock Metrics Service";
-
-
- const ENABLED_BY_DEFAULT = true;
-
- const STORE_FILENAME = "mstore.sqlite";
- const OLD_STORE_FILENAME = "mstore.js";
-
- const LOGGING_URL = "http://metrics.flock.com/anonusage.php";
-
- const PREF_FLOCK_METRICS_ENABLED = "flock.metrics.enabled";
-
- const PREF_FLOCK_METRICS_INTERVAL = "flock.metrics.interval";
- const DEFAULT_METRICS_INTERVAL = 86400;
-
- const PREF_FLOCK_FIRSTRUN_UUID = "flock.firstrun.uuid";
-
- const PREF_GENERAL_USERAGENT_EDITION = "general.useragent.edition";
- const PREF_GENERAL_USERAGENT_LOCALE = "general.useragent.locale";
-
- const PREF_DEFAULT_SEARCH_ENGINE = "browser.search.selectedEngine";
- const PREF_DEFAULT_ENGINE_NAME = "browser.search.defaultenginename";
- const PREF_BROWSER_STARTUP_HOMEPAGE = "browser.startup.homepage";
- const PREF_FEED_SELECTED_ACTION = "browser.feeds.handler";
-
- const PREF_FLOCK_FIRST_RUN_BIGDATE = "flock.first_run.bigDate";
-
- const URI_BRAND_PROPERTIES = "chrome://branding/locale/brand.properties";
-
- const MYWORLD_URL = "about:myworld";
-
- const HTTP_CODE_OK = 200;
-
- const IS_AUTHENTICATED_RSC = "http://flock.com/rdf#isAuthenticated";
- const IS_TRANSIENT_RSC = "http://flock.com/rdf#isTransient";
-
-
- const CC = Components.classes;
- const CI = Components.interfaces;
- const CR = Components.results;
- const CU = Components.utils;
-
- CU.import("resource:///modules/FlockXPCOMUtils.jsm");
- CU.import("resource://gre/modules/JSON.jsm");
- CU.import("resource:///modules/FlockCryptoHash.jsm");
-
-
- var gApp = null;
- var gPref = null;
- var gABI = null;
- var gOSVersion = null;
-
-
- function getObserverService() {
- return CC["@mozilla.org/observer-service;1"]
- .getService(CI.nsIObserverService);
- }
-
- function getCharPref(aPrefName, aDefaultValue) {
- if (gPref.getPrefType(aPrefName) == CI.nsIPrefBranch.PREF_STRING) {
- return gPref.getCharPref(aPrefName);
- } else {
- return aDefaultValue;
- }
- }
-
- function getIntPref(aPrefName, aDefaultValue) {
- if (gPref.getPrefType(aPrefName) == CI.nsIPrefBranch.PREF_INT) {
- return gPref.getIntPref(aPrefName);
- } else {
- return aDefaultValue;
- }
- }
-
- function getBoolPref(aPrefName, aDefaultValue) {
- if (gPref.getPrefType(aPrefName) == CI.nsIPrefBranch.PREF_BOOL) {
- return gPref.getBoolPref(aPrefName);
- } else {
- return aDefaultValue;
- }
- }
-
- function createStatement(aDBConn, aSQL) {
- var stmt = aDBConn.createStatement(aSQL);
- var wrapper = CC["@mozilla.org/storage/statement-wrapper;1"]
- .createInstance(CI.mozIStorageStatementWrapper);
- wrapper.initialize(stmt);
- return wrapper;
- }
-
-
- function MetricsService() {
- gApp = CC["@mozilla.org/xre/app-info;1"]
- .getService(CI.nsIXULAppInfo)
- .QueryInterface(CI.nsIXULRuntime);
-
- gPref = CC["@mozilla.org/preferences-service;1"]
- .getService(CI.nsIPrefBranch2)
-
- try {
- gABI = gApp.XPCOMABI;
-
- var macutils = CC["@mozilla.org/xpcom/mac-utils;1"];
- if (macutils) {
- if (macutils.getService(CI.nsIMacUtils).isUniversalBinary) {
- gABI = "Universal-gcc3";
- }
- }
- } catch (ex) {
- }
-
- try {
- var sysInfo = CC["@mozilla.org/system-info;1"]
- .getService(CI.nsIPropertyBag2);
- gOSVersion = sysInfo.getProperty("name") + " " +
- sysInfo.getProperty("version");
- } catch (ex) {
- }
-
- var obs = getObserverService();
-
- obs.addObserver(this, "flock-data-ready", false);
- obs.addObserver(this, "xpcom-shutdown", false);
-
- this.observe(null, "nsPref:changed", PREF_FLOCK_METRICS_ENABLED);
- }
-
- MetricsService.prototype = new FlockXPCOMUtils.genericComponent(
- MS_CLASSNAME,
- MS_CLASSID,
- MS_CONTRACTID,
- MetricsService,
- CI.nsIClassInfo.SINGLETON,
- [
- CI.flockIMetricsService,
- CI.flockIRDFObserver,
- CI.nsITimerCallback,
- CI.nsIObserver
- ]
- );
-
- MetricsService.prototype._xpcom_categories = [
- { category: "flock-startup", service: true }
- ];
-
-
- MetricsService.prototype._start =
- function MS__start() {
- this._logger = CC["@flock.com/logger;1"].createInstance(CI.flockILogger);
- this._logger.init("metrics");
- this._logger.info("starting up...");
-
- this._deleteOldStore();
-
- this.getUserUUID();
-
- this._coop = CC["@flock.com/singleton;1"]
- .getService(CI.flockISingleton)
- .getSingleton("chrome://flock/content/common/load-faves-coop.js")
- .wrappedJSObject;
-
- gPref.addObserver(PREF_FLOCK_METRICS_ENABLED, this, false);
- this.observe(null, "nsPref:changed", PREF_FLOCK_METRICS_ENABLED);
-
- this._watchLoginEvents();
-
- this.report("Browser-Start");
-
- gPref.addObserver(PREF_DEFAULT_SEARCH_ENGINE, this, false);
- gPref.addObserver(PREF_BROWSER_STARTUP_HOMEPAGE, this, false);
- gPref.addObserver(PREF_FEED_SELECTED_ACTION, this, false);
-
- var tm = CC["@mozilla.org/updates/timer-manager;1"]
- .getService(CI.nsIUpdateTimerManager);
- var interval = getIntPref(PREF_FLOCK_METRICS_INTERVAL,
- DEFAULT_METRICS_INTERVAL);
- tm.registerTimer("background-metrics-timer", this, interval);
- }
-
- MetricsService.prototype._shutdown =
- function MS__shutdown() {
- gApp = null;
- gPref = null;
- }
-
- MetricsService.prototype.notify =
- function MS_notify(aTimer) {
- this._sendReport();
- }
-
- MetricsService.prototype._configure =
- function MS__configure() {
- this._enabled = getBoolPref(PREF_FLOCK_METRICS_ENABLED, ENABLED_BY_DEFAULT);
-
- if (this._enabled) {
- this._createStore();
- } else {
- this._deleteStore();
- }
- }
-
- MetricsService.prototype._prefChanged =
- function MS__prefChanged(aPref) {
- switch (aPref) {
- case PREF_DEFAULT_SEARCH_ENGINE:
- this._reportDefaultSearchEngine();
- break;
-
- case PREF_BROWSER_STARTUP_HOMEPAGE:
- this._reportMyWorldStartPage();
- break;
-
- case PREF_FEED_SELECTED_ACTION:
- this._reportFeedReader();
- break;
-
- case PREF_FLOCK_METRICS_ENABLED:
- this._configure();
- break;
- }
- }
-
- MetricsService.prototype.observe =
- function MS_observe(aSubject, aTopic, aState) {
- var obs = getObserverService();
-
- switch (aTopic) {
- case "flock-data-ready":
- obs.removeObserver(this, "flock-data-ready");
- this._start();
- break;
-
- case "xpcom-shutdown":
- obs.removeObserver(this, "xpcom-shutdown");
- this._shutdown();
- break;
-
- case "nsPref:changed":
- this._prefChanged(aState);
- break;
- }
- }
-
- MetricsService.prototype._getProfileFile =
- function MS__getProfileFile(aFileName) {
- var file = CC["@mozilla.org/file/directory_service;1"]
- .getService(CI.nsIProperties)
- .get("ProfD", CI.nsILocalFile);
- file.append(aFileName);
- return file;
- }
-
- MetricsService.prototype._deleteOldStore =
- function MS__deleteOldStore() {
- var oldFile = this._getProfileFile(OLD_STORE_FILENAME);
-
- try {
- oldFile.remove(false);
- } catch (ex) {
- }
- }
-
- MetricsService.prototype._getMetricsDBFile =
- function MS__getMetricsDBFile() {
- return this._getProfileFile(STORE_FILENAME);
- }
-
- MetricsService.prototype._createStore =
- function MS__createStore() {
- var dbfile = this._getMetricsDBFile();
-
- var storageService = CC["@mozilla.org/storage/service;1"]
- .getService(CI.mozIStorageService);
- this._DBConn = storageService.openDatabase(dbfile);
-
- var schema = "key TEXT, value TEXT, type TEXT, time NUMBER";
-
- var alreadyCreated = this._DBConn.tableExists("metrics");
-
- if (!alreadyCreated) {
- try {
- this._DBConn.createTable("metrics", schema);
- } catch (ex) {
- this._DBConn = null;
- this._enabled = false;
- return;
- }
- }
-
- this._insertEvent = createStatement(this._DBConn,
- "INSERT INTO metrics (key, value, type, time) " +
- "VALUES (:key, :value, :type, :time)");
- this._getEvents = createStatement(this._DBConn,
- "SELECT * FROM metrics WHERE time <= :time");
- this._deleteEvents = createStatement(this._DBConn,
- "DELETE FROM metrics WHERE time <= :time");
-
- if (!alreadyCreated) {
- this._fillPrefInfo();
- }
- }
-
- MetricsService.prototype._deleteStore =
- function MS__deleteStore() {
- this._DBConn = null;
-
- var dbfile = this._getMetricsDBFile();
- try {
- dbfile.remove(false);
- } catch (ex) {
- }
- }
-
- MetricsService.prototype._expireStore =
- function MS__expireStore(aExpire) {
- if (!aExpire) {
- return;
- }
-
- var stmt = this._deleteEvents;
- stmt.reset();
- stmt.params.time = aExpire;
- stmt.step();
- }
-
- MetricsService.prototype.getUserUUID =
- function MS_getUserUUID() {
- var currentUUID = getCharPref(PREF_FLOCK_FIRSTRUN_UUID);
-
- if (!currentUUID) {
- var uuidGen = CC["@mozilla.org/uuid-generator;1"]
- .createInstance(CI.nsIUUIDGenerator);
- var uuid;
- try {
- uuid = uuidGen.generateUUID();
- } catch (ex) {
- // Doh, not enough randomness, we'll try again in the future
- return "0";
- }
-
- currentUUID = String(uuid).replace(/[{}]/g, "");
- gPref.setCharPref(PREF_FLOCK_FIRSTRUN_UUID, currentUUID);
- }
-
- return currentUUID;
- }
-
- MetricsService.prototype._getBaseInfo =
- function MS__getBaseInfo() {
- var sbs = CC["@mozilla.org/intl/stringbundle;1"]
- .getService(CI.nsIStringBundleService);
- var bundle = sbs.createBundle(URI_BRAND_PROPERTIES);
- var product = bundle.GetStringFromName("brandShortName");
-
- var edition = getCharPref(PREF_GENERAL_USERAGENT_EDITION, "");
- var uuid = this.getUserUUID();
-
- var locale;
- try {
- locale = gPref.getComplexValue(PREF_GENERAL_USERAGENT_LOCALE,
- nsIPrefLocalizedString).data;
- } catch (ex) {
- locale = getCharPref(PREF_GENERAL_USERAGENT_LOCALE);
- }
-
- var platform = gApp.OS + "_" + gABI;
-
- var defaultBrowser;
- try {
- if (CC["@mozilla.org/browser/shell-service;1"]
- .getService(CI.nsIShellService)
- .isDefaultBrowser(false))
- {
- defaultBrowser = "true";
- } else {
- defaultBrowser = "false";
- }
- } catch (ex) {
- defaultBrowser = "error";
- }
-
- var info = { "Browser-Product": product,
- "Browser-Version": gApp.version,
- "Browser-BuildID": gApp.appBuildID,
- "Browser-Edition": edition,
- "Browser-Locale": locale,
- "Browser-Platform": platform,
- "Browser-OSVersion": gOSVersion,
- "Browser-MetricsEnabled": this._enabled,
- "User-UUID": uuid,
- "Browser-ClientTime": null,
- "Browser-DefaultBrowser": defaultBrowser
- };
-
- var oldFirstRun = getCharPref(PREF_FLOCK_FIRST_RUN_BIGDATE);
- if (oldFirstRun) {
- info["User-FirstRun"] = oldFirstRun;
- }
-
- return info;
- }
-
- MetricsService.prototype._getFriendCounts =
- function MS__reportFriendCounts() {
- var friendCounts = [];
- var catMgr = CC["@mozilla.org/categorymanager;1"]
- .getService(CI.nsICategoryManager);
- var svcEnum = catMgr.enumerateCategory("flockWebService");
- while (svcEnum.hasMoreElements()) {
- var entry = svcEnum.getNext().QueryInterface(CI.nsISupportsCString);
- if (entry) {
- var contractID = catMgr.getCategoryEntry("flockWebService", entry.data);
- var svc = CC[contractID].getService(CI.flockIWebService);
- if (svc instanceof CI.flockISocialWebService) {
- var accounts = svc.getAccounts();
- while (accounts.hasMoreElements()) {
- var account = accounts.getNext()
- .QueryInterface(CI.flockISocialWebServiceAccount);
- friendCounts.push({service: svc.shortName,
- account: FlockCryptoHash.md5(account.urn),
- count: account.getFriendCount()});
- }
- }
- }
- }
- return friendCounts;
- }
-
- MetricsService.prototype._fillPrefInfo =
- function MS__fillPrefInfo() {
- this._reportDefaultSearchEngine();
- this._reportMyWorldStartPage();
- this._reportFeedReader();
- }
-
- MetricsService.prototype._reportDefaultSearchEngine =
- function MS__reportDefaultSearchEngine() {
- var defaultEngine;
- try {
- defaultEngine = gPref.getCharPref(PREF_DEFAULT_SEARCH_ENGINE);
- } catch (ex) {
- defaultEngine = gPref.getComplexValue(PREF_DEFAULT_ENGINE_NAME,
- CI.nsIPrefLocalizedString).data;
- }
-
- if (!defaultEngine)
- defaultEngine = "";
-
- this.report("SearchBox-DefaultSearchEngine", defaultEngine);
- }
-
- MetricsService.prototype._reportMyWorldStartPage =
- function MS__reportMyWorldStartPage() {
- var startPageHasMyWorld = false;
- try {
- var startPage = gPref.getComplexValue(PREF_BROWSER_STARTUP_HOMEPAGE,
- CI.nsIPrefLocalizedString).data;
- var startPages = startPage.split("|");
- for each (var url in startPages) {
- // Trim leading/trailing whitespace from URL
- url = url.replace(/(^\s+)|(\s+$)/g, "");
- if (url == MYWORLD_URL) {
- startPageHasMyWorld = true;
- break;
- }
- }
- } catch (ex) {
- }
-
- this.report("Browser-MyWorldIsHomePage", startPageHasMyWorld);
- }
-
- MetricsService.prototype._reportFeedReader =
- function MS__reportFeedReader() {
- var feedReader, action = getCharPref(PREF_FEED_SELECTED_ACTION);
-
- switch (action) {
- case "ask":
- feedReader = "news";
- break;
-
- case "bookmarks":
- feedReader = "livemarks";
- break;
-
- default:
- feedReader = "other";
- break;
- }
-
- this.report("Feeds-DefaultNewsReader", feedReader);
- }
-
- MetricsService.prototype._watchLoginEvents =
- function MS__watchLoginEvents() {
- const RDFS = CC["@mozilla.org/rdf/rdf-service;1"]
- .getService(CI.nsIRDFService);
-
- var faves = RDFS.GetDataSource("rdf:flock-favorites");
- faves.QueryInterface(CI.flockIRDFObservable);
-
- faves.addArcObserver(CI.flockIRDFObserver.TYPE_CHANGE, null,
- RDFS.GetResource(IS_AUTHENTICATED_RSC),
- null, this);
- faves.addArcObserver(CI.flockIRDFObserver.TYPE_CHANGE, null,
- RDFS.GetResource(IS_TRANSIENT_RSC),
- null, this);
- }
-
- MetricsService.prototype.rdfChanged =
- function MS_rdfChanged(aDS, aType, aSource, aPredicate, aTarget, aOldTarget) {
- if (aTarget instanceof CI.nsIRDFLiteral) {
- var account = this._coop.get_from_resource(aSource);
-
- if (aPredicate.ValueUTF8 == IS_AUTHENTICATED_RSC) {
- if (account.isAuthenticated) {
- this.report("Account-Login", account.serviceId);
- } else {
- this.report("Account-Logout", account.serviceId);
- }
- } else if (aPredicate.ValueUTF8 == IS_TRANSIENT_RSC) {
- if (!account.isTransient) {
- // The isTransient flag has changed. Please note that this will
- // only ever change from "true" to "false"; when the user opts to
- // "keep" the service. This means that we have to detect that the
- // user opted to "FORGET" The service we have to detect is elsewher
- // (as the whole account is deleted and the onChange event never
- // fires).
- this.report("Account-Keep", account.serviceId);
- }
- }
- }
- }
-
- MetricsService.prototype._getValueAndTypeForStorage =
- function MS__getValueAndTypeForStorage(aValue) {
- var value, type = typeof(aValue);
-
- switch (type) {
- case "undefined":
- value = null;
- break;
-
- case "string":
- value = aValue;
- break;
-
- case "boolean":
- case "number":
- value = aValue.toString();
- break;
-
- case "object":
- if (aValue) {
- var realValue;
-
- // Pull a single object out of a 1-element array
- if ("length" in aValue &&
- aValue.length === 1 &&
- aValue[0] &&
- typeof(aValue[0]) == "object")
- {
- realValue = aValue[0];
- } else {
- realValue = aValue;
- }
-
- // Need to make sure the object is JSON-safe, so we actually
- // do a full JSON convert here instead of .toSource()
- // and fall through to return null value if it fails
- try {
- value = "(" + JSON.toString(realValue) + ")";
- break;
- } catch (ex) {
- }
- }
- // fall through
-
- default:
- value = null;
- type = "undefined";
- break;
- }
-
- return [value, type];
- }
-
- MetricsService.prototype.report =
- function MS_report(aKey, aValue) {
- if (!this._enabled) {
- return;
- }
-
- try {
- var [value, type] = this._getValueAndTypeForStorage(aValue);
-
- var stmt = this._insertEvent;
- stmt.reset();
- pp = stmt.params;
- pp.key = aKey;
- pp.value = value;
- pp.type = type;
- pp.time = Date.now();
- stmt.step();
- } catch (ex) {
- }
- }
-
- MetricsService.prototype.getCurrentReport =
- function MS_getCurrentReport() {
- var [data, expire] = this._createReport();
- return data;
- }
-
- MetricsService.prototype.reportNow =
- function MS_reportNow(aKey, aValue) {
- /* XXX: only here to catch any users of the old API */
- this.report("old-reportNow-" + aKey, aValue);
- }
-
- MetricsService.prototype.reportCount =
- function MS_reportCount(aKey) {
- /* XXX: only here to catch any users of the old API */
- this.report("old-reportCount-" + aKey, null);
- }
-
- MetricsService.prototype._createReport =
- function MS__createReport() {
- var data = [];
- var baseInfo = this._getBaseInfo();
- var friendCounts = this._getFriendCounts();
- var now = Date.now();
- var expire = 0;
-
- if (this._enabled) {
- expire = now;
-
- var sandbox = new CU.Sandbox("about:blank");
-
- var stmt = this._getEvents;
- stmt.reset();
- stmt.params.time = expire;
-
- while (stmt.step()) {
- var row = stmt.row;
- var entry = { key: row.key, time: row.time };
- if (row.type == "string" || row.type == "undefined") {
- entry.value = row.value;
- } else {
- entry.value = CU.evalInSandbox(row.value, sandbox);
- }
- data.push(entry);
- }
- }
-
- for each (var value in friendCounts) {
- var entry = {key: "Account-FriendCount",
- value: value,
- time: now};
- data.push(entry);
- }
-
- for (let [key, value] in Iterator(baseInfo)) {
- var entry = { key: key, value: value, time: now };
- data.push(entry);
- }
-
- return [data, expire];
- }
-
- MetricsService.prototype._sendReport =
- function MS__sendReport() {
- var [data, expire] = this._createReport();
-
- if (gApp.appBuildID == "0000000000") {
- this._logger.debug("metrics packet: " + JSON.toString(data));
- this._expireStore(expire);
- return;
- }
-
- try {
- var compressor = CC["@flock.com/compress-content;1"]
- .createInstance(CI.flockICompressContent);
- var compressedData = compressor.compressString(JSON.toString(data));
-
- var xhr = CC["@mozilla.org/xmlextras/xmlhttprequest;1"]
- .createInstance(CI.nsIXMLHttpRequest);
-
- var self = this;
- xhr.onload = function MS__sendReportOnLoad(aEvent) {
- self._onLoad(aEvent, expire);
- };
- xhr.onerror = function MS__sendReportOnError(aEvent) {
- self._onError(aEvent);
- };
-
- xhr.backgroundRequest = true;
- xhr.open("POST", LOGGING_URL);
- xhr.send(compressedData);
- } catch (ex) {
- this._onError(null);
- }
- }
-
- MetricsService.prototype._onLoad =
- function MS__onLoad(aEvent, aExpire) {
- var xhr = aEvent.target;
- if (xhr.status == HTTP_CODE_OK) {
- this._expireStore(aExpire);
- }
- }
-
- MetricsService.prototype._onError =
- function MS__onError(aEvent) {
- // Some error happened while sending, don't clear the data
- }
-
- var gComponentsArray = [MetricsService];
-
- var NSGetModule = FlockXPCOMUtils.generateNSGetModule(MS_CLASSNAME,
- gComponentsArray);
-